package com.example.administrator.hospitalmap

import android.Manifest
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.location.Criteria
import android.location.Location
import android.location.LocationListener
import android.location.LocationManager
import android.os.Build
import android.os.Bundle
import android.support.v4.app.ActivityCompat
import android.support.v7.app.ActionBar
import android.support.v7.app.AppCompatActivity
import android.util.Log
import android.view.MenuItem
import android.widget.ArrayAdapter
import com.example.administrator.hospitalmap.entity.HospitalDetail
import com.google.android.gms.maps.*
import com.google.android.gms.maps.model.BitmapDescriptorFactory
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.Marker
import com.google.android.gms.maps.model.MarkerOptions
import com.tangula.android.utils.TaskUtils
import com.tangula.android.utils.ToastUtils
import com.tangula.utils.JsonUtils
import org.apache.commons.lang3.StringUtils


class MapActivity : AppCompatActivity(), OnMapReadyCallback, ActionBar.OnNavigationListener, LocationListener, LocationSource {

    val PREMISSION_REQUEST_CODE = 99

    var selectedRange = 0
    var currentLocation: Location? = null

    private var lcl: LocationSource.OnLocationChangedListener? = null

    private val markerMap = mutableMapOf<String, Marker>()

    private var mMap: GoogleMap? = null

    private lateinit var locationManager: LocationManager

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_map)

        if (Build.VERSION.SDK_INT >= 23) {
            ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION), PREMISSION_REQUEST_CODE)
        }

        beginListenLocations()
        // Obtain the SupportMapFragment and get notified when the map is ready to be used.
        val mapFragment = supportFragmentManager
                .findFragmentById(R.id.map) as SupportMapFragment
        mapFragment.getMapAsync(this)

        supportActionBar?.apply {
            setTitle(R.string.title_activity_maps)
            setDisplayHomeAsUpEnabled(true)
            setHomeButtonEnabled(true)

            navigationMode = ActionBar.NAVIGATION_MODE_LIST

            ArrayAdapter(this@MapActivity, R.layout.item_range, HostpitalMapApplication.CUR_APP.SEARCH_ACTIONS).also {
                setListNavigationCallbacks(it, this@MapActivity)
            }

        }
    }

    fun beginListenLocations() {
        locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager

        val criteria = Criteria()
        criteria.accuracy = Criteria.ACCURACY_FINE
        criteria.isAltitudeRequired = false
        criteria.isBearingRequired = false
        criteria.isCostAllowed = true
        criteria.powerRequirement = Criteria.POWER_HIGH

        var provider = locationManager.getBestProvider(criteria, true)

        Log.v("console", "best provider:$provider")

        val providerList = locationManager.getProviders(true)
        when {
            providerList.contains(LocationManager.GPS_PROVIDER) -> provider = LocationManager.GPS_PROVIDER
            providerList.contains(LocationManager.NETWORK_PROVIDER) -> provider = LocationManager.NETWORK_PROVIDER
        }

        if (StringUtils.isBlank(provider) && !providerList.isEmpty()) {
            provider = providerList[0]
        }

        if (StringUtils.isNotBlank(provider)) {
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
                    || ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
                Log.w("console", "start requestLocationUpdates-----$provider")
                locationManager.requestLocationUpdates(provider, 5000L, 5.0f, this)
            }
        } else {
            ToastUtils.showToastLong("Please Open Your GPS or Location Service ")
            providerList.forEach {
                Log.v("console", "provider:$it")
            }
        }

    }

    /**
     * Manipulates the map once available.
     * This callback is triggered when the map is ready to be used.
     * This is where we can add markers or lines, add listeners or move the camera. In this case,
     * we just add a marker near Sydney, Australia.
     * If Google Play services is not installed on the device, the user will be prompted to install
     * it inside the SupportMapFragment. This method will only be triggered once the user has
     * installed Google Play services and returned to the app.
     */
    override fun onMapReady(googleMap: GoogleMap) {
        mMap = googleMap


        mMap!!.setOnMarkerClickListener {
            if (it.tag is HospitalDetail) {
                clickHospital(it.tag as HospitalDetail)
            }
            true
        }

        mMap!!.uiSettings.apply {
            isZoomControlsEnabled = true
            isZoomGesturesEnabled = true
            isScrollGesturesEnabled = true
            isCompassEnabled = true
            isMyLocationButtonEnabled = true
        }

        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
                || ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
            mMap!!.isMyLocationEnabled = true
        }

        mMap!!.setMinZoomPreference(4.0f)
        mMap!!.setMaxZoomPreference(18.0f)
        mMap!!.moveCamera(CameraUpdateFactory.zoomBy(1.0f))
        mMap!!.moveCamera(CameraUpdateFactory.zoomTo(15.0f))

        mMap!!.setLocationSource(this)


    }


    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        if (item.itemId == android.R.id.home) {
            finish()
            return true
        }
        return super.onOptionsItemSelected(item)
    }

    override fun onNavigationItemSelected(itemPosition: Int, itemId: Long): Boolean {
        selectedRange = itemPosition
        whenSelectSearchDistanceOrMove(selectedRange, HostpitalMapApplication.CUR_APP.SEARCH_ACTIONS[selectedRange])
        return false
    }

    var whenSelectSearchDistanceOrMove = { index: Int, _: String ->

        HostpitalMapApplication.CUR_APP.loadHospitals(index) {

            TaskUtils.runInUiThread {
                it.forEach {
                    if (currentLocation != null) {

                        val distance = currentLocation!!.distanceTo(Location(LocationManager.GPS_PROVIDER).apply {
                            latitude = it.lat.toDouble()
                            longitude = it.lot.toDouble()
                        })

                        val range = HostpitalMapApplication.CUR_APP.convSearchActionIndex2SearchDistance(selectedRange)

                        Log.v("console", "distance:${distance}, range:$range, ${distance<=range} ${it.id}")

                        if (distance <= range && !markerMap.containsKey(it.id)) {
                            addToMap(it, distance.toInt())
                        }

                        if(distance > range){
                            removeFromMap(it)
                        }

                    } else {
                        if (!markerMap.containsKey(it.id)) {
                            addToMap(it, -1)
                        }
                    }
                }
            }


        }


    }

    private fun addToMap(hd: HospitalDetail, distance: Int) {
        mMap?.addMarker(MarkerOptions().position(LatLng(hd.lat.toDouble(), hd.lot.toDouble())).also {
            if(distance>=0){
                it.icon(BitmapDescriptorFactory.fromResource(
                        when(distance){
                            in 0 .. 1000->R.mipmap.ic_marker_hospital_blue
                            in 1001 .. 10000->R.mipmap.ic_marker_hospital_green
                            in 10001 .. 20000->R.mipmap.ic_marker_hospital_yellow
                            in 20001 .. 30000->R.mipmap.ic_marker_hospital_orange
                            else->R.mipmap.ic_marker_hospital_red
                        }
                ))
            }
        })?.also {
            it.tag = hd
            markerMap.put(hd.id, it)
        }
    }

    private fun removeFromMap(hd: HospitalDetail) {
        Log.v("console", "remove ${hd.id}")
        markerMap[hd.id]?.also {
            it.remove()
            markerMap.remove(hd.id)
        }
    }

    private fun clickHospital(detail: HospitalDetail) {
        startActivity(
            Intent(this, DetailActivity::class.java).apply {
                this.putExtra("hospital", JsonUtils.toJson(detail))
            }
        )
    }

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        when (requestCode) {
            PREMISSION_REQUEST_CODE -> {
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    beginListenLocations()
                    // Obtain the SupportMapFragment and get notified when the map is ready to be used.
                    val mapFragment = supportFragmentManager
                            .findFragmentById(R.id.map) as SupportMapFragment
                    mapFragment.getMapAsync(this)
                } else {
                    ToastUtils.showToastLong("Please grant GPS permissions!")
                }
            }
        }
    }

    // ----- location listener begein
    override fun onLocationChanged(location: Location) {
        Log.v("console", "location change:${location.latitude} ${location.longitude}")
        currentLocation = location
        lcl?.also {
            it.onLocationChanged(location)
            mMap?.moveCamera(CameraUpdateFactory.newLatLng(LatLng(location.latitude, location.longitude)))
        }
        whenSelectSearchDistanceOrMove(selectedRange, HostpitalMapApplication.CUR_APP.SEARCH_ACTIONS[selectedRange])
    }

    override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {
    }

    override fun onProviderEnabled(provider: String?) {
    }

    override fun onProviderDisabled(provider: String?) {
    }

    // ----- location listener end


    // ---- location source

    override fun deactivate() {
        lcl = null
    }

    override fun activate(p0: LocationSource.OnLocationChangedListener?) {
        lcl = p0
    }


}
